package net.lastcoder.ifserver.util;

/**XXTea
 * auth: WenYF
 * date: 2017/8/2
 */
public class XXTea {
    /**把字节码转为十六进制码，一个字节两个十六进制，内部为字符串分配空间
     * 小写
     * @param data
     * @return
     */
    public static String byteToHex(byte[] data) {
        StringBuilder stringBuilder = new StringBuilder("");
        if (data == null || data.length <= 0) {
            return null;
        }
        for (int i = 0; i < data.length; i++) {
            int v = data[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    /**把十六进制字符串，转为字节码，每两个十六进制字符作为一个字节
     * @param hex
     * @return
     */
    public static byte[] hexToByte(String hex) {
        if (hex == null) {
            return null;
        }

        if (TextUtils.isEmpty(hex))
            return null;

        //16进制转大写
        hex = hex.toUpperCase();
        byte[] hexData = hex.getBytes();

        // 数据缓冲区
        byte[] pbBuf = new byte[hexData.length / 2];

        boolean ret = true;
        do {
            int tmp1, tmp2;
            for (int i = 0; i < hexData.length / 2; i++) {
                tmp1 = (int)hexData[i * 2] - (((int)hexData[i * 2] >= 'A') ? 'A' - 10 : '0');

                if (tmp1 >= 16) {
                    ret = false;
                    break;
                }

                tmp2 = (int)hexData[i * 2 + 1] - (((int)hexData[i * 2 + 1] >= 'A') ? 'A' - 10 : '0');

                if (tmp2 >= 16) {
                    ret = false;
                    break;
                }

                pbBuf[i] = (byte) (tmp1 * 16 + tmp2);
            }
        }
        while (false);

        if (ret) {
            return pbBuf;
        }

        return null;
    }

    /**
     * Encrypt data with key.
     *
     * @param data
     * @return
     */
    public static byte[] encrypt(byte[] data) {
        if (data.length == 0) {
            return data;
        }
        return toByteArray(
                encrypt(toIntArray(data, true)), false);
    }

    /**
     * Decrypt data with key.
     *
     * @param data
     * @return
     */
    public static byte[] decrypt(byte[] data) {
        if (data.length == 0) {
            return data;
        }
        return toByteArray(
                decrypt(toIntArray(data, false)), true);
    }

    public static int[] k = new int[] {
            0x32124A78,0x4D5494D5,0x4D030A25,0x1F2CC23B,0x6EEE2225,0xBA2751B1,0xAA4DEB31,0xA399F97C,0x996B2035,0x25EA1850,0xD8EA60D1,0xD01430D7,0x8840B0DA,0xF4266731,0xCE36F6D7,0x2BC4066E,0x51687F84,0xCCA5FA16,0xBFC87A52,0x791356A1,0x481B7AE5,0x926FD0FF,0x217AF895,0xBFAB3F12,0x3D3CFEE,0x6ACE232F,0xA965BE30,0x42731DA1,0x5647EACF,0xBA4A7225,0x4DE159F3,0x88958C6F
    };

    /**
     * Encrypt data with key.
     *
     * @param v
     * @return
     */
    public static int[] encrypt(int[] v) {
        int n = v.length;
        int y;
        int p;
        int rounds = 6 + 52/n;
        int sum = 0;
        int z = v[n-1];
        int delta = 0x9E3779B9;
        do {
            sum += delta;
            int e = (sum >>> 2) & 3;
            for (p=0; p<n-1; p++) {
                y = v[p+1];
                z = v[p] += (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
            }
            y = v[0];
            z = v[n-1] += (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
        } while (--rounds > 0);
        return v;
    }
    /**
     * Decrypt data with key.
     *
     * @param v
     * @return
     */
    public static int[] decrypt(int[] v) {
        int n = v.length;
        int z = v[n - 1], y = v[0], delta = 0x9E3779B9, sum, e;
        int p;
        int rounds = 6 + 52/n;
        sum = rounds*delta;
        y = v[0];
        do {
            e = (sum >>> 2) & 3;
            for (p=n-1; p>0; p--) {
                z = v[p-1];
                y = v[p] -= (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
            }
            z = v[n-1];
            y = v[0] -= (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
        } while ((sum -= delta) != 0);
        return v;
    }

    /**
     * Convert byte array to int array.
     *
     * @param data
     * @param includeLength
     * @return
     */
    private static int[] toIntArray(byte[] data, boolean includeLength) {
        int n = (((data.length & 3) == 0)
                ? (data.length >>> 2)
                : ((data.length >>> 2) + 1));
        int[] result;

        if (includeLength) {
            result = new int[n + 1];
            result[n] = data.length;
        } else {
            result = new int[n];
        }
        n = data.length;
        for (int i = 0; i < n; i++) {
            result[i >>> 2] |= (0x000000ff & data[i]) << ((i & 3) << 3);
        }
        return result;
    }

    /**
     * Convert int array to byte array.
     *
     * @param data
     * @param includeLength
     * @return
     */
    private static byte[] toByteArray(int[] data, boolean includeLength) {
        int n = data.length << 2;

        if (includeLength) {
            int m = data[data.length - 1];

            if (m > n) {
                return null;
            } else {
                n = m;
            }
        }

        byte[] result = new byte[n];

        for (int i = 0; i < n; i++) {
            result[i] = (byte) ((data[i >>> 2] >>> ((i & 3) << 3)) & 0xff);
        }
        return result;
    }
}